package com.caoustc.okhttplib.utils

import android.os.Environment
import android.text.TextUtils
import okhttp3.MediaType
import java.io.*
import java.net.URLConnection
import java.util.*

class FileUtils private constructor() {
    companion object {
        const val FILE_EXTENSION_SEPARATOR = "."
        fun readFile(filePath: String?, charsetName: String?): StringBuilder? {
            val file = File(filePath)
            val fileContent = StringBuilder("")
            if (file == null || !file.isFile) {
                return null
            }
            var reader: BufferedReader? = null
            return try {
                val `is` = InputStreamReader(FileInputStream(file), charsetName)
                reader = BufferedReader(`is`)
                var line: String? = null
                while (reader.readLine().also { line = it } != null) {
                    if (fileContent.toString() != "") {
                        fileContent.append("\r\n")
                    }
                    fileContent.append(line)
                }
                reader.close()
                fileContent
            } catch (e: IOException) {
                throw RuntimeException("IOException occurred. ", e)
            } finally {
                if (reader != null) {
                    try {
                        reader.close()
                    } catch (e: IOException) {
                        throw RuntimeException("IOException occurred. ", e)
                    }
                }
            }
        }

        @JvmOverloads
        fun writeFile(filePath: String, content: String?, append: Boolean = false): Boolean {
            if (StringUtils.Companion.isEmpty(content)) {
                return false
            }
            var fileWriter: FileWriter? = null
            return try {
                makeDirs(filePath)
                fileWriter = FileWriter(filePath, append)
                fileWriter.write(content)
                fileWriter.close()
                true
            } catch (e: IOException) {
                throw RuntimeException("IOException occurred. ", e)
            } finally {
                if (fileWriter != null) {
                    try {
                        fileWriter.close()
                    } catch (e: IOException) {
                        throw RuntimeException("IOException occurred. ", e)
                    }
                }
            }
        }

        @JvmOverloads
        fun writeFile(
            filePath: String,
            contentList: List<String>,
            append: Boolean = false
        ): Boolean {
            if (ListUtils.isEmpty(contentList)) {
                return false
            }
            var fileWriter: FileWriter? = null
            return try {
                makeDirs(filePath)
                fileWriter = FileWriter(filePath, append)
                var i = 0
                for (line in contentList) {
                    if (i++ > 0) {
                        fileWriter.write("\r\n")
                    }
                    fileWriter.write(line)
                }
                fileWriter.close()
                true
            } catch (e: IOException) {
                throw RuntimeException("IOException occurred. ", e)
            } finally {
                if (fileWriter != null) {
                    try {
                        fileWriter.close()
                    } catch (e: IOException) {
                        throw RuntimeException("IOException occurred. ", e)
                    }
                }
            }
        }

        @JvmOverloads
        fun writeFile(filePath: String?, stream: InputStream, append: Boolean = false): Boolean {
            return writeFile(if (filePath != null) File(filePath) else null, stream, append)
        }

        @JvmOverloads
        fun writeFile(file: File?, stream: InputStream, append: Boolean = false): Boolean {
            var o: OutputStream? = null
            return try {
                makeDirs(file!!.absolutePath)
                o = FileOutputStream(file, append)
                val data = ByteArray(1024)
                var length = -1
                while (stream.read(data).also { length = it } != -1) {
                    o.write(data, 0, length)
                }
                o.flush()
                true
            } catch (e: FileNotFoundException) {
                throw RuntimeException("FileNotFoundException occurred. ", e)
            } catch (e: IOException) {
                throw RuntimeException("IOException occurred. ", e)
            } finally {
                if (o != null) {
                    try {
                        o.close()
                        stream.close()
                    } catch (e: IOException) {
                        throw RuntimeException("IOException occurred. ", e)
                    }
                }
            }
        }

        fun moveFile(sourceFilePath: String?, destFilePath: String?) {
            if (TextUtils.isEmpty(sourceFilePath) || TextUtils.isEmpty(destFilePath)) {
                throw RuntimeException("Both sourceFilePath and destFilePath cannot be null.")
            }
            moveFile(File(sourceFilePath), File(destFilePath))
        }

        fun moveFile(srcFile: File, destFile: File) {
            val rename = srcFile.renameTo(destFile)
            if (!rename) {
                copyFile(srcFile.absolutePath, destFile.absolutePath)
                deleteFile(srcFile.absolutePath)
            }
        }

        fun copyFile(sourceFilePath: String?, destFilePath: String?): Boolean {
            var inputStream: InputStream  = try {
                FileInputStream(sourceFilePath)
            } catch (e: FileNotFoundException) {
                throw RuntimeException("FileNotFoundException occurred. ", e)
            }
            return writeFile(destFilePath, inputStream)
        }

        fun readFileToList(filePath: String?, charsetName: String?): List<String?>? {
            val file = File(filePath)
            val fileContent: MutableList<String?> = ArrayList()
            if (file == null || !file.isFile) {
                return null
            }
            var reader: BufferedReader? = null
            return try {
                val `is` = InputStreamReader(FileInputStream(file), charsetName)
                reader = BufferedReader(`is`)
                var line: String? = null
                while (reader.readLine().also { line = it } != null) {
                    fileContent.add(line)
                }
                reader.close()
                fileContent
            } catch (e: IOException) {
                throw RuntimeException("IOException occurred. ", e)
            } finally {
                if (reader != null) {
                    try {
                        reader.close()
                    } catch (e: IOException) {
                        throw RuntimeException("IOException occurred. ", e)
                    }
                }
            }
        }

        fun getFileNameWithoutExtension(filePath: String): String {
            if (StringUtils.Companion.isEmpty(filePath)) {
                return filePath
            }
            val extenPosi = filePath.lastIndexOf(FILE_EXTENSION_SEPARATOR)
            val filePosi = filePath.lastIndexOf(File.separator)
            if (filePosi == -1) {
                return if (extenPosi == -1) filePath else filePath.substring(0, extenPosi)
            }
            if (extenPosi == -1) {
                return filePath.substring(filePosi + 1)
            }
            return if (filePosi < extenPosi) filePath.substring(
                filePosi + 1,
                extenPosi
            ) else filePath.substring(filePosi + 1)
        }

        fun getFileName(filePath: String): String {
            if (StringUtils.Companion.isEmpty(filePath)) {
                return filePath
            }
            val filePosi = filePath.lastIndexOf(File.separator)
            return if (filePosi == -1) filePath else filePath.substring(filePosi + 1)
        }

        fun getFolderName(filePath: String): String {
            if (StringUtils.Companion.isEmpty(filePath)) {
                return filePath
            }
            val filePosi = filePath.lastIndexOf(File.separator)
            return if (filePosi == -1) "" else filePath.substring(0, filePosi)
        }

        fun getFileExtension(filePath: String): String {
            if (StringUtils.Companion.isBlank(filePath)) {
                return filePath
            }
            val extenPosi = filePath.lastIndexOf(FILE_EXTENSION_SEPARATOR)
            val filePosi = filePath.lastIndexOf(File.separator)
            if (extenPosi == -1) {
                return ""
            }
            return if (filePosi >= extenPosi) "" else filePath.substring(extenPosi + 1)
        }

        fun makeDirs(filePath: String): Boolean {
            val folderName = getFolderName(filePath)
            if (StringUtils.Companion.isEmpty(folderName)) {
                return false
            }
            val folder = File(folderName)
            return if (folder.exists() && folder.isDirectory) true else folder.mkdirs()
        }

        fun makeFolders(filePath: String): Boolean {
            return makeDirs(filePath)
        }

        fun makeFolders(filePath: File): Boolean {
            return makeDirs(filePath.absolutePath)
        }

        fun isFileExist(filePath: String?): Boolean {
            if (StringUtils.Companion.isBlank(filePath)) {
                return false
            }
            val file = File(filePath)
            return file.exists() && file.isFile
        }

        fun isFolderExist(directoryPath: String?): Boolean {
            if (StringUtils.Companion.isBlank(directoryPath)) {
                return false
            }
            val dire = File(directoryPath)
            return dire.exists() && dire.isDirectory
        }

        fun deleteFile(path: String?): Boolean {
            if (StringUtils.Companion.isBlank(path)) {
                return true
            }
            val file = File(path)
            if (!file.exists()) {
                return true
            }
            if (file.isFile) {
                return file.delete()
            }
            if (!file.isDirectory) {
                return false
            }
            for (f in file.listFiles()) {
                if (f.isFile) {
                    f.delete()
                } else if (f.isDirectory) {
                    deleteFile(f.absolutePath)
                }
            }
            return file.delete()
        }

        fun getFileSize(path: String?): Long {
            if (StringUtils.Companion.isBlank(path)) {
                return -1
            }
            val file = File(path)
            return if (file.exists() && file.isFile) file.length() else -1
        }

        val isSDCard: Boolean
            get() = Environment.getExternalStorageState() ==
                    Environment.MEDIA_MOUNTED
        val sDDownloadDirPath: String
            get() {
                val path =
                    Environment.getExternalStorageDirectory().absolutePath + File.separator + "nbcbb" + File.separator
                if (!isFolderExist(path)) {
                    val dirs = makeDirs(path)
                }
                return path
            }

        fun getSDDownloadFilePath(filePath: String): String {
            val path = sDDownloadDirPath + filePath
            if (!isFolderExist(path)) {
                makeDirs(path)
            }
            return path
        }

        val aPKVersionPath: String
            get() = getAPKVersionPath(false)

        fun getAPKVersionPath(isDelete: Boolean): String {
            val path = getSDDownloadFilePath("apk" + File.separator + "nbcbb.apk")
            if (isDelete && isFileExist(path)) {
                deleteFile(path)
            }
            return path
        }

        val imageDiscCache: String
            get() {
                val path = getSDDownloadFilePath("cache/image/")
                if (!isFolderExist(path)) {
                    makeDirs(path)
                }
                return path
            }
        val updateImageCache: String
            get() {
                val path = getSDDownloadFilePath("cache/updateImage/")
                if (!isFolderExist(path)) {
                    makeDirs(path)
                }
                return path
            }

        fun guessMimeType(path: String): MediaType? {
            var path = path
            val fileNameMap = URLConnection.getFileNameMap()
            path = path.replace("#", "") //解决文件名中含有#号异常的问题
            var contentType = fileNameMap.getContentTypeFor(path)
            if (contentType == null) {
                contentType = "application/octet-stream"
            }
            return MediaType.parse(contentType)
        }
    }

    init {
        throw AssertionError()
    }
}